#ifndef P2P_INTERFACE_H
#define P2P_INTERFACE_H

class CRtMessageBlock;
class CRtInetAddr;
class CRtString;
class IMessageBusSink;

typedef DWORD NodeIDType;
#define NODE_UNREGISTERED 1

typedef enum
{
	NODE_TYPE_NONE,
	NODE_TYPE_ORDINARY,
	NODE_TYPE_SUPER
}NodeType;

typedef enum
{
	GROUP_TYPE_NONE = 0,
	GROUP_TYPE_P2P,
	GROUP_TYPE_PART_P2P,
	GROUP_TYPE_SN_ONLY
}GroupType;

class RT_API_EXPORT IMessageBus
{
public:
	/*
	 *	IMessageBus will be a singleton, Instance() will return the static instatnce of IMessageBus
	 */
	static IMessageBus*	Instance();
public:
	/*
	 *	 Initialize the instance,
	 * Parameters:
	 *   listendAddr: local listen addr for messagebus, every bus should listen at a unique address;
	 *   nType: instance is run as ordinary node or super node;
	 *   pSink: the callback instance;
	 *   dwInitID: specify the base nodeID of the cluster. 
	 *             if dwInitID==0, all nodeIDs of the cluster will be set as IP values,
	 *             else, the super node ID will be set as dwInitID and all its ordinary node IDs will 
	 *             be based on it. 
	 * return:
	 *   RT_OK: successfully, otherwise failed.
	 */
	virtual RtResult Initialize(const CRtInetAddr& listenAddr, 
								NodeType nType,
								IMessageBusSink* pSink,
								const char* strClusterID,
								DWORD dwInitID = 0) = 0;
	virtual void Release() = 0;

	/*
	 *	for super node, it is add other super nodes,
	 *  for ordinary node, it is add super nodes address.
	 * Parameters:
	 *    addr: peer's address.
	 * return:
	 *   RT_OK: successfully, otherwise failed;
	 */
	virtual RtResult AddPeer(const CRtInetAddr& addr, const CRtInetAddr* p2ndAddr = NULL) = 0;

	/*
	 *	remove peer node.
	 */
	virtual RtResult RemovePeer(const CRtInetAddr& addr) = 0;
	
	/*
	 *	join a group
	 * Parameters:
*  groupName: group name
*  nType: group type, to indicate whether p2p, or part p2p, or by super ndoe
	 *    bReceiveSelf: when callback the messgae which send by itself.
	 */
	virtual RtResult JoinGroup(const CRtString& groupName,
								GroupType nType,
								BOOL bReceiveSelf= FALSE) = 0;
	/*
	 *	leave group.
	 */
	virtual RtResult LeaveGroup(const CRtString& groupName) = 0;

	/*
	 *	broad cast a message to a group.
	 */
	virtual RtResult MultiCast(const CRtString& groupname,
								CRtMessageBlock& msg,
								BOOL bUrgent) = 0;

	/*
	 * Send message to a peer node.
	 * In our application, NodeID values of some supper nodes are probably 
	 * changed due to substitution of active GC, so we have to introduce 
	 * a new parameter named bNotRelay, to point out whether the peer node 
	 * needs to transmit the message to other nodes when receiving it. 
	 * If bNotRelay==TRUE, it may just call IMessageBusSink::OnMessage() of 
	 * its sink and does not have to transmit the message to others.
	 */
	virtual RtResult Unicast(NodeIDType nodeid,
							CRtMessageBlock& msg,
							BOOL bNotRelay = FALSE) = 0;

	virtual RtResult SetOpt(DWORD dwOptType,
							void* lpOptValue) = 0;

	virtual RtResult GetOpt(DWORD dwOptType,
							void*& lpValue) = 0;

	virtual NodeIDType GetLocalNodeID() = 0;
	virtual NodeIDType GetSuperNodeID() = 0;

	/*
	 *	helper api, get peer's id by address
	 */
	//virtual RtResult CheckPeerIDByAddr(const CRtInetAddr& addr, NodeIDType& nodeid) = 0;

	virtual RtResult StartListen2ndAddr(const CRtInetAddr& addr) = 0;
	virtual void StopListen2ndAddr() = 0;

	/*
	 * This api is only for supper node.
	 */
	virtual void RemoveLocalNodes() = 0;
	virtual void RemoveNode(NodeIDType dwNodeID) = 0;
	virtual const CRtString& GetNodeClusterID(NodeIDType dwNodeID) = 0;

protected:
	virtual ~IMessageBus() {}
};

class IMessageBusSink
{
public:
	virtual void OnNodeJoin(const CRtString& grouname, NodeIDType nodeID, NodeIDType superNodeID, const CRtInetAddr& addr) = 0 ;
	virtual void OnNodeLeave(const CRtString& groupname, NodeIDType nodeID, NodeIDType superNodeID) = 0 ;
	/*
	 *	receive message callback, if groupname is not null, then it get from a multicast, otherwise it is unicast.
	 */
	virtual void OnMessage(NodeIDType nodeid,
							CRtMessageBlock& msg,
							const CRtString& groupname) = 0;

protected:
	virtual ~IMessageBusSink() {}
};

#endif
